/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package treccontextsug;

import de.l3s.boilerpipe.BoilerpipeProcessingException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.simple.parser.ParseException;
import org.xml.sax.SAXException;

/**
 *
 * @author manzato
 */
public class TRECContextSug {

    //private final static String datasetPath = "/home/ditusp/Databases/TREC/";
    private final static String datasetPath = "/Users/manzato/Databases/TREC/";
    //private final static String datasetPath = "/home/marcelo/Databases/TREC/";
    //private final static String outputFile = "/home/ditusp/Desktop/output.csv";
    private final static String outputFile = "/Users/manzato/Desktop/output.csv";
    //private final static String outputFile = "/home/marcelo/Desktop/output.csv";
    //private final static String subcollectionPath = datasetPath + "trecCS2013-subcollection/";
    private final static String subcollectionPath = datasetPath + "clueweb12-descriptions/";

    private static HashMap<String, Result> condenseList(ArrayList<Result> list) {
        HashMap<String, Result> condensed = new HashMap();
        Iterator i = list.iterator();
        if (i.hasNext()) {
            Result ant = (Result) i.next();
            double weight = ant.ranking;
            while (i.hasNext()) {
                Result res = (Result) i.next();
                if (ant.docId.equals(res.docId)) {
                    weight += res.ranking;
                } else {
                    ant.ranking = weight;
                    condensed.put(ant.docId, ant);
                    weight = res.ranking;
                }
                ant = res;
            }
        }
        return condensed;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        //run01 - We extracted interesting and non interesting keywords from the examples, and based on them, we created personalized queries for each user. Then, we used the Lucene Search Engine to query the set of attractions based on the descriptions available on the websites. The set of documents was created based on the ClueQWeb12-CS, which was filtered using the Google Places API.

        SuggestionsOutput out = new SuggestionsOutput(outputFile, "run01");
        ProfilesSet profileReader = new ProfilesSet(datasetPath + "profiles2013.json");
        ContextsSet contextReader = new ContextsSet(datasetPath + "contexts2013.json");
        ExamplesSet exampleReader = new ExamplesSet(datasetPath + "examples_enrich2013.json");
        try {
            profileReader.readJSON();
            contextReader.readJSON();
            exampleReader.readJSON();

            profileReader.buildProfiles(exampleReader);

            for (Context context : contextReader.getAllContexts()) {

//                if (!context.getCity().equals("Lima")) {
//                    continue;
//                }

                LuceneSearch search = new LuceneSearch();

                //ReadSubcollectionJSON readerSub = new ReadSubcollectionJSON(subcollectionPath);
                ReadSubcollectionJSON readerSub = new ReadSubcollectionJSON(subcollectionPath);
                readerSub.fillLuceneSearcher(context, search);
                search.optimize();

                // THIS IS ONLY FOR TESTING - BEGIN
//                {
//                    System.out.println("Type a query: ");
//                    Scanner s = new Scanner(System.in);
//                    String query = "";
//                    while (!(query = s.nextLine()).equals("exit")) {
//                        Result[] res = search.search(query);
//                        if (res != null) {
//                            System.out.print("Query '" + query + "' returned " + res.length + " results: ");
//                        } else {
//                            System.out.println("Query '" + query + "' returned 0 results.");
//                        }
//                        for (int i = 0; res != null && i < res.length; i++) {
//                            System.out.println(res[i].docId + "(" + res[i].ranking + "), ");
//                        }
//                    }
//                }
                // THIS IS ONLY FOR TESTING - END


                for (Profile profile : profileReader.getAllProfiles()) {
                    //TODO: CREATE PERSONALIZED QUERY
                    String[] positiveQueries = profile.getPositiveQueries();
                    String[] negativeQueries = profile.getNegativeQueries();

                    //TODO: QUERY LUCENE
                    ArrayList<Result> posRes = new ArrayList();
                    for (String posQuery : positiveQueries) {
                        Result[] res = search.search(posQuery);
                        if (res != null) {
                            posRes.addAll(Arrays.asList(res));
                        }
                    }
                    ArrayList<Result> negRes = new ArrayList();
                    for (String negQuery : negativeQueries) {
                        Result[] res = search.search(negQuery);
                        if (res != null) {
                            negRes.addAll(Arrays.asList(res));
                        }
                    }

                    //TODO: FILTER RESULTS
                    Collections.sort(posRes, new Comparator<Result>() {
                        @Override
                        public int compare(Result o1, Result o2) {
                            return (o1.docId.compareTo(o2.docId));
                        }
                    });
                    Collections.sort(negRes, new Comparator<Result>() {
                        @Override
                        public int compare(Result o1, Result o2) {
                            return (o1.docId.compareTo(o2.docId));
                        }
                    });

                    HashMap<String, Result> posResFiltered = condenseList(posRes);
                    HashMap<String, Result> negResFiltered = condenseList(negRes);

                    ArrayList<Result> mergedList = mergeLists(posResFiltered, negResFiltered);

                    //TODO: PERSONALIZE ATTRACTIONS DESCRIPTIONS AND TITLE

                    //TODO: ADD SUGGESTIONS INTO OUTPUT FILE WITH SPECIFIED TREC FORMAT
                    Collections.sort(mergedList);
                    Collections.reverse(mergedList);
                    int rank = 1;
                    for (Result r : mergedList) {
                        out.addSuggestion(profile.getId(), context.getId(), rank++, r.title, r.description, r.url);
                        if (rank > 50) {
                            break;
                        }
                    }
                }
            }
        } catch (FileNotFoundException ex) {
            Logger.getLogger(ProfilesSet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(ProfilesSet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParseException ex) {
            Logger.getLogger(TRECContextSug.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(TRECContextSug.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BoilerpipeProcessingException ex) {
            Logger.getLogger(TRECContextSug.class.getName()).log(Level.SEVERE, null, ex);
        }
        out.closeFile();
    }

    private static ArrayList<Result> mergeLists(HashMap<String, Result> pos, HashMap<String, Result> neg) {
        Set<String> posKeys = pos.keySet();
        ArrayList<Result> retVal = new ArrayList();
        for (String posId : posKeys) {
            Result posRes = pos.get(posId);
            if (neg.containsKey(posId)) {
                Result negRes = neg.get(posId);
                posRes.ranking -= negRes.ranking;
            }
            retVal.add(posRes);
        }
        return retVal;
    }
}
